import { BuildingType, DirectionType, EntityType, TildeType, UnitType } from '../../battle/Enums';
import { UnitConfig } from '../../battle/Const';
import { LOG } from '../../ConsoleLogCtrl';

/**
 * 地图格子数据
 */
export interface MapTile {
    // 坐标
    x: number;
    y: number;
    // 地块类型
    tileType: TildeType;
    // 归属玩家ID
    playerId?: string;
    // 实体ID
    entityId?: number;
    // 实体类型
    entityType?: EntityType;
    // 单位类型
    unitType?: UnitType;
    // 建筑类型
    buildingType?: BuildingType;
}

/**
 * 地图管理器类
 * 用于维护战斗中的实时地图数据
 */
export class MapManager {
    // 地图数据二维数组
    private mapData: MapTile[][];
    // 地图尺寸
    public mapWidth: number;
    public mapHeight: number;

    /**
     * 构造函数
     */
    constructor() {}

    /**
     * 重置地图状态
     * 清空所有实体数据，保留地形信息
     */
    public reset(): void {
        if (!this.mapData) {
            return;
        }

        // 遍历所有地图格子，清除实体相关数据
        for (let y = 0; y < this.mapHeight; y++) {
            for (let x = 0; x < this.mapWidth; x++) {
                const tile = this.mapData[y][x];
                // 保留坐标和地形类型，清除实体相关数据
                tile.playerId = undefined;
                tile.entityId = undefined;
                tile.entityType = undefined;
                tile.unitType = undefined;
                tile.buildingType = undefined;
            }
        }

        LOG.log('地图已重置，所有实体数据已清空');
    }

    /**
     * 初始化地图
     * @param initialMapData 初始地图数据（必传）
     */
    public initMap(initialMapData: number[][]): void {
        this.mapHeight = initialMapData.length;
        this.mapWidth = initialMapData[0].length;
        this.mapData = [];

        // 初始化地图数据
        for (let y = 0; y < this.mapHeight; y++) {
            this.mapData[y] = [];
            for (let x = 0; x < this.mapWidth; x++) {
                this.mapData[y][x] = {
                    x,
                    y,
                    tileType: initialMapData[y][x] as TildeType
                };
            }
        }

        LOG.log('地图初始化完成，尺寸:', this.mapWidth, 'x', this.mapHeight);
    }

    /**
     * 放置实体到地图上
     * @param entityTile 包含实体信息的地图块对象
     * @returns 是否放置成功
     */
    public placeEntity(entityTile: MapTile): boolean {
        const { x, y, playerId, entityType, entityId, unitType, buildingType } = entityTile;

        // 检查坐标是否有效
        if (!this.isValidPosition(x, y)) {
            LOG.error(`放置实体失败：无效的坐标 (${x}, ${y})，地图尺寸: ${this.mapWidth}x${this.mapHeight}`);
            return false;
        }

        const currentTile = this.mapData[y][x];

        // 检查目标位置是否可放置（必须是平地且没有其他实体）
        if (currentTile.tileType !== TildeType.flat) {
            LOG.error(`放置实体失败：目标位置 (${x}, ${y}) 不是平地，当前地形类型: ${currentTile.tileType}`);
            return false;
        }

        if (currentTile.entityId !== undefined) {
            LOG.error(`放置实体失败：目标位置 (${x}, ${y}) 已被占用，现有实体ID: ${currentTile.entityId}, 玩家: ${currentTile.playerId}`);
            return false;
        }

        // 更新地图数据
        this.mapData[y][x].playerId = playerId;
        this.mapData[y][x].entityType = entityType;
        this.mapData[y][x].entityId = entityId;

        // 根据实体类型设置单位或建筑类型
        if (entityType === EntityType.unit && unitType !== undefined) {
            this.mapData[y][x].unitType = unitType;
        } else if (entityType === EntityType.building && buildingType !== undefined) {
            this.mapData[y][x].buildingType = buildingType;
        }

        LOG.log(`实体已放置：(${x},${y}), 玩家:${playerId}, 实体ID:${entityId}, 类型:${entityType}`);
        return true;
    }

    /**
     * 移除地图上的实体
     * @param x X坐标
     * @param y Y坐标
     * @returns 是否移除成功
     */
    public removeEntity(x: number, y: number): boolean {
        // 检查坐标是否有效
        if (!this.isValidPosition(x, y)) {
            LOG.error('移除实体失败：无效的坐标', x, y);
            return false;
        }

        // 检查目标位置是否有实体
        if (this.mapData[y][x].entityId === undefined) {
            LOG.error('移除实体失败：目标位置没有实体', x, y);
            return false;
        }

        // 记录被移除的实体信息（用于日志）
        const entityInfo = {
            playerId: this.mapData[y][x].playerId,
            entityType: this.mapData[y][x].entityType,
            entityId: this.mapData[y][x].entityId
        };

        // 清除实体相关数据
        this.mapData[y][x].playerId = undefined;
        this.mapData[y][x].entityType = undefined;
        this.mapData[y][x].entityId = undefined;
        this.mapData[y][x].unitType = undefined;
        this.mapData[y][x].buildingType = undefined;

        LOG.log(`实体已移除：(${x},${y}), 玩家:${entityInfo.playerId}, 实体ID:${entityInfo.entityId}`);
        return true;
    }

    /**
     * 移动实体
     * @param fromX 起始X坐标
     * @param fromY 起始Y坐标
     * @param toX 目标X坐标
     * @param toY 目标Y坐标
     * @returns 是否移动成功
     */
    public moveEntity(fromX: number, fromY: number, toX: number, toY: number): boolean {
        // 检查坐标是否有效
        if (!this.isValidPosition(fromX, fromY) || !this.isValidPosition(toX, toY)) {
            LOG.error('移动实体失败：无效的坐标', fromX, fromY, toX, toY);
            return false;
        }

        // 检查起始位置是否有实体
        if (this.mapData[fromY][fromX].entityId === undefined) {
            LOG.error('移动实体失败：起始位置没有实体', fromX, fromY);
            return false;
        }

        // 检查目标位置是否可移动（必须是平地且没有其他实体，河流不可移动）
        if (this.mapData[toY][toX].tileType !== TildeType.flat || this.mapData[toY][toX].entityId !== undefined) {
            LOG.error('移动实体失败：目标位置不可移动', toX, toY);
            return false;
        }

        // 获取实体信息
        const entityInfo = {
            playerId: this.mapData[fromY][fromX].playerId,
            entityType: this.mapData[fromY][fromX].entityType,
            entityId: this.mapData[fromY][fromX].entityId,
            unitType: this.mapData[fromY][fromX].unitType,
            buildingType: this.mapData[fromY][fromX].buildingType
        };

        // 先在目标位置放置实体
        const placeResult = this.placeEntity({
            x: toX,
            y: toY,
            tileType: TildeType.flat,
            playerId: entityInfo.playerId,
            entityType: entityInfo.entityType,
            entityId: entityInfo.entityId,
            unitType: entityInfo.unitType,
            buildingType: entityInfo.buildingType
        });

        // 如果放置成功，再移除起始位置的实体
        if (placeResult) {
            // 清除起始位置的实体相关数据（不使用removeEntity避免重复日志）
            this.mapData[fromY][fromX].playerId = undefined;
            this.mapData[fromY][fromX].entityType = undefined;
            this.mapData[fromY][fromX].entityId = undefined;
            this.mapData[fromY][fromX].unitType = undefined;
            this.mapData[fromY][fromX].buildingType = undefined;
        } else {
            return false;
        }

        LOG.log(`实体已移动：(${fromX},${fromY}) -> (${toX},${toY}), 实体ID:${entityInfo.entityId}`);
        return true;
    }

    /**
     * 判断指定方向是否存在实体
     * @param x 当前X坐标
     * @param y 当前Y坐标
     * @param direction 方向
     * @returns 是否存在实体
     */
    public hasEntityInDirection(x: number, y: number, direction: DirectionType): boolean {
        const [targetX, targetY] = this.getPositionInDirection(x, y, direction);

        // 检查坐标是否有效
        if (!this.isValidPosition(targetX, targetY)) {
            return false;
        }

        // 检查目标位置是否有实体
        return this.mapData[targetY][targetX].entityId !== undefined;
    }

    /**
     * 判断指定方向是否存在对手实体
     * @param x 当前X坐标
     * @param y 当前Y坐标
     * @param playerId 当前玩家ID
     * @param direction 方向
     * @returns 是否存在对手实体
     */
    public hasOpponentEntityInDirection(x: number, y: number, playerId: string, direction: DirectionType): boolean {
        const [targetX, targetY] = this.getPositionInDirection(x, y, direction);

        // 检查坐标是否有效
        if (!this.isValidPosition(targetX, targetY)) {
            return false;
        }

        // 检查目标位置是否有实体，且不属于当前玩家
        return this.mapData[targetY][targetX].entityId !== undefined &&
               this.mapData[targetY][targetX].playerId !== playerId;
    }

    /**
     * 获取地图数据
     * @returns 地图数据二维数组
     */
    public getMapData(): MapTile[][] {
        return this.mapData;
    }

    /**
     * 获取指定位置的地图格子数据
     * @param x X坐标
     * @param y Y坐标
     * @returns 地图格子数据，如果坐标无效则返回undefined
     */
    public getTile(x: number, y: number): MapTile | undefined {
        if (this.isValidPosition(x, y)) {
            return this.mapData[y][x];
        }
        return undefined;
    }

    /**
     * 检查坐标是否有效
     * @param x X坐标
     * @param y Y坐标
     * @returns 坐标是否有效
     */
    public isValidPosition(x: number, y: number): boolean {
        return x >= 0 && x < this.mapWidth && y >= 0 && y < this.mapHeight;
    }

    /**
     * 获取指定方向的坐标
     * @param x 当前X坐标
     * @param y 当前Y坐标
     * @param direction 方向
     * @returns 目标坐标 [x, y]
     */
    public getPositionInDirection(x: number, y: number, direction: DirectionType): [number, number] {
        switch (direction) {
            case DirectionType.UP:
                return [x, y - 1];
            case DirectionType.RIGHT:
                return [x + 1, y];
            case DirectionType.DOWN:
                return [x, y + 1];
            case DirectionType.LEFT:
                return [x - 1, y];
            default:
                return [x, y];
        }
    }

    /**
     * 判断单位是否可以移动到指定方向
     * @param unitId 单位ID
     * @param playerId 玩家ID
     * @param direction 方向
     * @returns 是否可以移动
     */
    public canUnitMoveToDirection(unitId: number, playerId: string, direction: DirectionType): boolean {
        // 首先找到单位的当前位置
        let unitPosition: { x: number; y: number } | null = null;

        for (let y = 0; y < this.mapHeight; y++) {
            for (let x = 0; x < this.mapWidth; x++) {
                const tile = this.mapData[y][x];
                if (tile.entityId === unitId && tile.playerId === playerId && tile.entityType === EntityType.unit) {
                    unitPosition = { x, y };
                    break;
                }
            }
            if (unitPosition) break;
        }

        if (!unitPosition) {
            return false;
        }

        // 获取目标位置
        const [targetX, targetY] = this.getPositionInDirection(unitPosition.x, unitPosition.y, direction);

        // 检查目标位置是否有效
        if (!this.isValidPosition(targetX, targetY)) {
            return false;
        }

        // 检查目标位置是否可移动（必须是平地且没有其他实体，河流不可移动）
        const targetTile = this.mapData[targetY][targetX];
        return targetTile.tileType === TildeType.flat && targetTile.entityId === undefined;
    }

    /**
     * 判断单位是否可以攻击指定方向的实体
     * @param unitId 单位ID
     * @param playerId 玩家ID
     * @param direction 方向
     * @returns 是否可以攻击
     */
    public canUnitAttackInDirection(unitId: number, playerId: string, direction: DirectionType): boolean {
        // 首先找到单位的当前位置和类型
        let unitPosition: { x: number; y: number } | null = null;
        let unitType: UnitType | undefined = undefined;

        for (let y = 0; y < this.mapHeight; y++) {
            for (let x = 0; x < this.mapWidth; x++) {
                const tile = this.mapData[y][x];
                if (tile.entityId === unitId && tile.playerId === playerId && tile.entityType === EntityType.unit) {
                    unitPosition = { x, y };
                    unitType = tile.unitType;
                    break;
                }
            }
            if (unitPosition) break;
        }

        if (!unitPosition || !unitType) {
            return false;
        }

        // 获取单位的攻击范围
        const unitConfig = UnitConfig[unitType];
        const attackRange = unitConfig ? unitConfig.attackRange : 1;

        // 检查攻击范围内是否有对手实体
        for (let dy = -attackRange; dy <= attackRange; dy++) {
            for (let dx = -attackRange; dx <= attackRange; dx++) {
                // 跳过自己的位置
                if (dx === 0 && dy === 0) {
                    continue;
                }

                // 只允许四个方向攻击（上下左右），不允许斜向攻击
                if ((dx !== 0 && dy !== 0) || Math.abs(dx) > attackRange || Math.abs(dy) > attackRange) {
                    continue;
                }

                const targetX = unitPosition.x + dx;
                const targetY = unitPosition.y + dy;

                // 检查目标位置是否有效
                if (!this.isValidPosition(targetX, targetY)) {
                    continue;
                }

                // 检查攻击路径是否被阻挡（攻击范围大于1的单位可以穿越河流攻击）
                if (attackRange > 1) {
                    // 攻击范围大于1的单位可以穿越河流，但不能穿越山丘
                    if (!this.canAttackThroughTerrain(unitPosition.x, unitPosition.y, targetX, targetY)) {
                        continue;
                    }
                } else {
                    // 攻击范围为1的单位不能穿越任何地形障碍
                    if (!this.isDirectPathClear(unitPosition.x, unitPosition.y, targetX, targetY)) {
                        continue;
                    }
                }

                // 检查目标位置是否有对手实体
                const targetTile = this.mapData[targetY][targetX];
                if (targetTile.entityId !== undefined && targetTile.playerId !== playerId) {
                    // 如果指定了方向，检查目标是否在该方向上
                    if (direction !== undefined) {
                        const [directionX, directionY] = this.getPositionInDirection(unitPosition.x, unitPosition.y, direction);
                        if (targetX === directionX && targetY === directionY) {
                            return true;
                        }
                    } else {
                        // 如果没有指定方向，只要攻击范围内有对手实体就返回true
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检查单位是否可以在指定方向治疗友军单位
     * @param unitId 单位ID
     * @param playerId 玩家ID
     * @param direction 方向
     * @returns 是否可以治疗
     */
    public canUnitHealInDirection(unitId: number, playerId: string, direction: DirectionType): boolean {
        // 首先找到单位的当前位置和类型
        let unitPosition: { x: number; y: number } | null = null;
        let unitType: UnitType | undefined = undefined;

        for (let y = 0; y < this.mapHeight; y++) {
            for (let x = 0; x < this.mapWidth; x++) {
                const tile = this.mapData[y][x];
                if (tile.entityId === unitId && tile.playerId === playerId && tile.entityType === EntityType.unit) {
                    unitPosition = { x, y };
                    unitType = tile.unitType;
                    break;
                }
            }
            if (unitPosition) break;
        }

        if (!unitPosition || !unitType) {
            return false;
        }

        // 获取单位的治疗范围（使用attackRange作为治疗范围）
        const unitConfig = UnitConfig[unitType];
        const healRange = unitConfig ? unitConfig.attackRange : 1;

        // 检查治疗范围内是否有友军单位
        for (let dy = -healRange; dy <= healRange; dy++) {
            for (let dx = -healRange; dx <= healRange; dx++) {
                // 跳过自己的位置
                if (dx === 0 && dy === 0) {
                    continue;
                }

                // 只允许四个方向治疗（上下左右），不允许斜向治疗
                if ((dx !== 0 && dy !== 0) || Math.abs(dx) > healRange || Math.abs(dy) > healRange) {
                    continue;
                }

                const targetX = unitPosition.x + dx;
                const targetY = unitPosition.y + dy;

                // 检查目标位置是否有效
                if (!this.isValidPosition(targetX, targetY)) {
                    continue;
                }

                // 检查目标位置是否有友军单位
                const targetTile = this.mapData[targetY][targetX];
                if (targetTile.entityId !== undefined && targetTile.playerId === playerId && targetTile.entityType === EntityType.unit) {
                    // 如果指定了方向，检查目标是否在该方向上
                    if (direction !== undefined) {
                        const [directionX, directionY] = this.getPositionInDirection(unitPosition.x, unitPosition.y, direction);
                        if (targetX === directionX && targetY === directionY) {
                            return true;
                        }
                    } else {
                        // 如果没有指定方向，只要治疗范围内有友军单位就返回true
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检查攻击范围大于1的单位是否可以穿越地形攻击目标
     * 河流可以穿越，山丘不可以穿越
     * @param fromX 起始X坐标
     * @param fromY 起始Y坐标
     * @param toX 目标X坐标
     * @param toY 目标Y坐标
     * @returns 是否可以穿越攻击
     */
    private canAttackThroughTerrain(fromX: number, fromY: number, toX: number, toY: number): boolean {
        // 对于攻击范围大于1的单位，检查路径上是否有山丘阻挡
        const dx = Math.abs(toX - fromX);
        const dy = Math.abs(toY - fromY);

        // 只检查直线路径（上下左右）
        if (dx > 0 && dy > 0) {
            return false; // 不允许斜向攻击
        }

        // 检查路径上的每个格子
        const stepX = toX > fromX ? 1 : (toX < fromX ? -1 : 0);
        const stepY = toY > fromY ? 1 : (toY < fromY ? -1 : 0);

        let currentX = fromX + stepX;
        let currentY = fromY + stepY;

        while (currentX !== toX || currentY !== toY) {
            if (!this.isValidPosition(currentX, currentY)) {
                return false;
            }

            const tile = this.mapData[currentY][currentX];
            // 山丘阻挡攻击，河流不阻挡
            if (tile.tileType === TildeType.hill) {
                return false;
            }

            currentX += stepX;
            currentY += stepY;
        }

        return true;
    }

    /**
     * 检查攻击范围为1的单位的直接路径是否畅通
     * 河流和山丘都会阻挡
     * @param fromX 起始X坐标
     * @param fromY 起始Y坐标
     * @param toX 目标X坐标
     * @param toY 目标Y坐标
     * @returns 路径是否畅通
     */
    private isDirectPathClear(fromX: number, fromY: number, toX: number, toY: number): boolean {
        // 对于攻击范围为1的单位，只能攻击相邻的格子
        const dx = Math.abs(toX - fromX);
        const dy = Math.abs(toY - fromY);

        // 只允许攻击相邻格子（上下左右）
        if ((dx === 1 && dy === 0) || (dx === 0 && dy === 1)) {
            // 检查目标位置的地形，河流和山丘都不能直接攻击
            const targetTile = this.mapData[toY][toX];
            return targetTile.tileType === TildeType.flat ||
                   targetTile.tileType === TildeType.energy ||
                   targetTile.tileType === TildeType.wood ||
                   targetTile.tileType === TildeType.stone ||
                   targetTile.tileType === TildeType.gold;
        }

        return false;
    }
}